"""

.. module:: a2pdatastore_servicetest
.. moduleauthor:: @author: 

The purpose of this module is test the A2PDataStoreService class.
   
.. seealso:: class :class:`spear.a2pdatastore_service.A2PDataStoreService`

*Constants*:
"""

# Imports
#
import logging
import unittest
from datetime import datetime

from datastore.database import DataStore, NotFoundException
from datastore.resource import Resource
from datastore.spaces import Spaces
from datastore.uri import Uri
from runtime.rt import Runtime
from spear.a2p_service import A2PService
from runtime.nodelogger import NodeLogger

# Constants
#

# Classes
#

class A2PDataStoreServiceTest(unittest.TestCase):
    """
    This class is a unit test for A2PDataStoreService. 

    **Constants**:
    """

    @staticmethod
    def init():
        A2PDataStoreServiceTest.datastore = DataStore(filename="U:\\yarra-node-test\\eplanning.datastore")
        A2PDataStoreServiceTest.spaces = Spaces()
        
        # Initialise Runtime and Spaces. This results in the loading of spaces' 
        # namespace bindings.
        #
        rt = Runtime(A2PDataStoreServiceTest.datastore)
        rt.spaces = A2PDataStoreServiceTest.spaces
        rt.start_service_manager_and_config_service()
        
        A2PDataStoreServiceTest.logger = NodeLogger.getLogger('eplanning.spear.a2pdatastore_servicetest')
    
    def setUp(self):
        """
        This function initialises the unit test.
        """
        
        self.logger = A2PDataStoreServiceTest.logger
        self.spaces = A2PDataStoreServiceTest.spaces

        A2PDataStoreServiceTest.is_calledback = False
        
    def tearDown(self):
        """
        This function finalises the unit test.
        
        :param param_1: <class> or <type>
        :param param_2: <class> or <type>
        :rtype: <return type>
        """
        
        self.logger.log(logging.DEBUG, "===================== tearDown()")
    
    def cb_callback(self, uri, action, rs):
        self.logger.log(logging.DEBUG, "===================== watch callback, uri (%s), action (%s), rs (%s)" % (uri, action, rs))
        
        A2PDataStoreServiceTest.is_calledback = True
        
        self.logger.log(logging.DEBUG, "===================== cb_callback")
        
        if (rs is not None):
            self.spaces.remove(uri)
            
    def test_1_process_spear_application_updates(self):
        """
        This function tests A2PDataStoreService::cb_process_spear_application_updates(). 
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource.
        #
        app_rs = Resource(type='term:eplanning/spear/application')
        app_rs.set_metadata(Uri('term:base/runtime/active'), False)
        app_rs.set_metadata(Uri('spearReferenceNumber'), 'S1234567J')
        app_rs.set_var('date_created', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        app_rs.set_var('spearAppToken', '987654')
        app_rs.set_var('sid002b_dict', {})
        app_rs.set_var('state', A2PService.APPSTATE_NOINFO)
        app_rs.set_var('outstanding_attachments_list', [])
        
        spear_app_uri = Uri('spear:app').add('S1234567J')
        response_uri = self.spaces.put(spear_app_uri, app_rs)
        self.spaces.set_watch(response_uri, self.cb_callback, filter=['put'])
        
        found = False
        
        # check datastore for Resource.
        #
        try:
            rs_list = self.datastore.find([(Uri('term:base/datastore/resource/type'), Uri('term:eplanning/spear/application')),
                                           (Uri('spearReferenceNumber'), 'S1234567J')])
        except NotFoundException:
            pass
        else:
            if (rs_list is not None) and \
               (len(rs_list) > 0):
                found = True
        
        self.assertEqual(found, True, "Spear application Resource not found")
        
    def test_2_process_spear_application_deletes(self):
        """
        This function tests A2PDataStoreService::cb_process_spear_application_deletes().
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Use the Spear application Resource created in the first test.
        #
        
        spear_app_uri = Uri('spear:app').add('S1234567J')
        self.spaces.remove(spear_app_uri)
        
        found = False
        
        # check datastore for Resource.
        #
        try:
            rs_list = self.datastore.find([(Uri('term:base/datastore/resource/type'), Uri('term:eplanning/spear/application')),
                                           (Uri('spearReferenceNumber'), 'S1234567J')])
        except NotFoundException:
            pass
        else:
            if (rs_list is not None) and \
               (len(rs_list) > 0):
                found = True
        
        self.assertNotEqual(found, True, "Spear application Resource found")
        
    def test_3_process_spear_application_retrievals(self):
        """
        This function tests A2PDataStoreService::cb_process_spear_application_retrievals().
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource and write it directly to the
        # DataStore (ie. not via Spaces).
        #
        app_rs = Resource(type='term:eplanning/spear/application')
        app_rs.set_metadata(Uri('term:base/runtime/active'), False)
        app_rs.set_metadata(Uri('spearReferenceNumber'), 'S1234567J')
        app_rs.set_var('date_created', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        app_rs.set_var('spearAppToken', '987654')
        app_rs.set_var('sid002b_dict', {})
        app_rs.set_var('state', A2PService.APPSTATE_NOINFO)
        app_rs.set_var('outstanding_attachments_list', [])
        
        self.datastore.put(app_rs)
        
        # Test 2 deleted the Spear application Resource from Spaces and the
        # DataStore. Therefore the following Spaces::get() should be forced 
        # to go to the DataStore for the (above) Resource.
        #
        
        spear_app_uri = Uri('spear:app').add('S1234567J')
        app_rs = self.spaces.get(spear_app_uri)
        
        found = False
        
        if (app_rs is not None) and \
           (app_rs.metadata_has_key(Uri('spearReferenceNumber')) is True) and \
           (app_rs.get_metadata(Uri('spearReferenceNumber')) == 'S1234567J'):
            found = True
        
        # cleanup
        #
        self.spaces.remove(spear_app_uri)
        
        self.assertEqual(found, True, "Spear application Resource not found")
        
    def test_4_process_spear_attachment_updates(self):
        """
        This function tests A2PDataStoreService::cb_process_spear_attachment_updates(). 
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource.
        #
        app_attach_rs = Resource(type='term:eplanning/spear/application-attachment')
        app_attach_rs.set_metadata(Uri('term:base/runtime/active'), False)
        app_attach_rs.set_metadata(Uri('spearReferenceNumber'), 'S1234567J')
        app_attach_rs.set_metadata(Uri('documentId'), '123')
        app_attach_rs.set_var('date_created', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        app_attach_rs.set_var('pdf', None)
    
        spear_attach_uri = Uri('spear:app-attachment/') + 123
        response_uri = self.spaces.put(spear_attach_uri, app_attach_rs)
        self.spaces.set_watch(response_uri, self.cb_callback, filter=['put'])
        
        found = False
        
        # check datastore for Resource.
        #
        try:
            rs_list = self.datastore.find([(Uri('term:base/datastore/resource/type'), Uri('term:eplanning/spear/application-attachment')),
                                           (Uri('spearReferenceNumber'), 'S1234567J'),
                                           (Uri('documentId'), 123)])
        except NotFoundException:
            pass
        else:
            if (rs_list is not None):
                if (len(rs_list) == 1):
                    found = True
                elif (len(rs_list) > 1):
                    self.fail("More than one Spear attachment in datastore.")
        
        self.assertEqual(found, True, "Spear application Resource not found")
        
    def test_5_process_spear_attachment_deletes(self):
        """
        This function tests A2PDataStoreService::cb_process_spear_attachment_deletes().
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource.
        #
        app_attach_rs = Resource(type='term:eplanning/spear/application-attachment')
        app_attach_rs.set_metadata(Uri('term:base/runtime/active'), False)
        app_attach_rs.set_metadata(Uri('spearReferenceNumber'), 'S1234567J')
        app_attach_rs.set_metadata(Uri('documentId'), '123')
        app_attach_rs.set_var('date_created', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        app_attach_rs.set_var('pdf', None)
    
        spear_attach_uri = Uri('spear:app-attachment/') + 123
        self.spaces.put(spear_attach_uri, app_attach_rs)
        
        # Now remove it.
        #
        spear_attach_uri = Uri('spear:app-attachment/') + 123
        self.spaces.remove(spear_attach_uri)
        
        found = False
        
        # check datastore for Resource.
        #
        try:
            rs_list = self.datastore.find([(Uri('term:base/datastore/resource/type'), Uri('term:eplanning/spear/application-attachment')),
                                           (Uri('spearReferenceNumber'), 'S1234567J'),
                                           (Uri('documentId'), 123)])
        except NotFoundException:
            pass
        else:
            if (rs_list is not None):
                if (len(rs_list) == 1):
                    found = True
                elif (len(rs_list) > 1):
                    self.fail("More than one Spear attachment in datastore.")
        
        self.logger.log(logging.DEBUG, "****** after remove, found (%s)" % found)
        self.assertEqual(found, False, "Spear attachment Resource found")
        
    def test_6_process_spear_attachment_retrievals(self):
        """
        This function tests A2PDataStoreService::cb_process_spear_attachment_retrievals().
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource.
        #
        app_attach_rs = Resource(type='term:eplanning/spear/application-attachment')
        app_attach_rs.set_metadata(Uri('term:base/runtime/active'), False)
        app_attach_rs.set_metadata(Uri('spearReferenceNumber'), 'S1234567J')
        app_attach_rs.set_metadata(Uri('documentId'), '123')
        app_attach_rs.set_var('date_created', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        app_attach_rs.set_var('pdf', None)
        
        self.datastore.put(app_attach_rs)
        
        # Test 5 deleted the Spear attachment Resource from Spaces and the
        # DataStore. Therefore the following Spaces::get() should be forced 
        # to go to the DataStore for the Resource.
        #
        
        spear_attach_uri = Uri('spear:app-attachment/') + 123
        app_attach_rs = self.spaces.get(spear_attach_uri)
        
        found = False
        
        if (app_attach_rs is not None) and \
           (app_attach_rs.metadata_has_key(Uri('spearReferenceNumber')) is True) and \
           (app_attach_rs.get_metadata(Uri('spearReferenceNumber')) == 'S1234567J') and \
           (app_attach_rs.metadata_has_key(Uri('documentId')) is True) and \
           (app_attach_rs.get_metadata(Uri('documentId')) == '123'):
            found = True
        
        # cleanup
        #
        self.spaces.remove(spear_attach_uri)
        
        self.assertEqual(found, True, "Spear attachment Resource not found")
    
    def test_7_process_a2p_control_updates(self):
        """
        This function tests A2PDataStoreService::cb_process_a2p_control_updates(). 
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource.
        #
        control_rs = Resource(type='term:eplanning/spear/a2p-control')
        control_rs.set_metadata(Uri('term:base/runtime/active'), False)
        control_rs.set_var('last_poll_time', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        
        control_rs_uri = Uri('spear:a2p-control')
        response_uri = self.spaces.put(control_rs_uri, control_rs)
        self.spaces.set_watch(response_uri, self.cb_callback, filter=['put'])
        
        found = False
        
        # check datastore for Resource.
        #
        try:
            rs_list = self.datastore.find([(Uri('term:base/datastore/resource/type'), Uri('term:eplanning/spear/a2p-control'))])
        except NotFoundException:
            pass
        else:
            if (rs_list is not None) and \
               (len(rs_list) > 0):
                found = True
        
        self.assertEqual(found, True, "A2P Control Resource not found")
        
    def test_8_process_a2p_control_deletes(self):
        """
        This function tests A2PDataStoreService::cb_process_a2p_control_deletes().
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Use the Spear application Resource created in the first test.
        #
        
        spear_app_uri = Uri('spear:a2p-control')
        self.spaces.remove(spear_app_uri)
        
        found = False
        
        # check datastore for Resource.
        #
        try:
            rs_list = self.datastore.find([(Uri('term:base/datastore/resource/type'), Uri('term:eplanning/spear/a2p-control'))])
        except NotFoundException:
            pass
        else:
            if (rs_list is not None) and \
               (len(rs_list) > 0):
                found = True
        
        self.assertNotEqual(found, True, "A2P Control Resource found")
        
    def test_9_process_a2p_control_retrievals(self):
        """
        This function tests A2PDataStoreService::cb_process_a2p_control_retrievals().
        """
        
        self.logger.log(logging.DEBUG, "")
        
        # Create a Spear application Resource and write it directly to the
        # DataStore (ie. not via Spaces).
        #
        control_rs = Resource(type='term:eplanning/spear/a2p-control')
        control_rs.set_metadata(Uri('term:base/runtime/active'), False)
        control_rs.set_var('last_poll_time', datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        
        self.datastore.put(control_rs)
        
        # Test 2 deleted the Spear application Resource from Spaces and the
        # DataStore. Therefore the following Spaces::get() should be forced 
        # to go to the DataStore for the (above) Resource.
        #
        
        control_rs_uri = Uri('spear:a2p-control')
        control_rs = self.spaces.get(control_rs_uri)
        
        found = False
        
        if (control_rs is not None):
            found = True
        
        # cleanup
        #
        self.spaces.remove(control_rs_uri)
        
        self.assertEqual(found, True, "A2P Control Resource not found")
    
if __name__ == "__main__":
    A2PDataStoreServiceTest.init()
    unittest.main()